package fr.pp.tcxhandler.launch;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.xml.bind.JAXBElement;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;

import fr.pp.tcxhandler.bean.ActivityLapT;
import fr.pp.tcxhandler.bean.ActivityT;
import fr.pp.tcxhandler.bean.LXT;
import fr.pp.tcxhandler.bean.SportT;
import fr.pp.tcxhandler.bean.TPXT;
import fr.pp.tcxhandler.bean.TcxExt;
import fr.pp.tcxhandler.bean.TrackT;
import fr.pp.tcxhandler.bean.TrackpointT;
import fr.pp.tcxhandler.bean.TrainingCenterDatabaseT;

/**
 * 
 * @author Pascuit
 * 
 */
public class TcxSpeedCalculator {

	private static final String FILE_NAME = "src/main/resources/tcx/input.tcx";
	private Unmarshaller jaxb2Unmarshaller;
	private Marshaller jaxb2Marshaller;

	public static void main(String[] args) throws IOException, DatatypeConfigurationException {
		ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");

		TcxSpeedCalculator app = appContext.getBean(TcxSpeedCalculator.class);
		TrainingCenterDatabaseT tcx = app.loadGpxWithJaxb2(FILE_NAME);

		app.handlerTcx(tcx, 70, 38, 16);
		app.convertFromObjectToXMLWithJaxb2(tcx, "output.tcx");
	}

	public void handlerTcx(TrainingCenterDatabaseT tcx, int poids, int plateaux, int pignon)
			throws DatatypeConfigurationException {
		double gear = (double) plateaux / pignon;
		double tour = (double) (gear * 2.099);

		for (ActivityT activity : tcx.getActivities().getActivity()) {
			// activity.setId(getXmlCalendar());
			activity.setNotes("Braquet :" + plateaux + "/" + pignon);
			activity.setSport(SportT.BIKING);

			List<ActivityLapT> laps = activity.getLap();

			int cadenceCount = 0;
			int trackPointCount = 0;
			for (ActivityLapT lap : laps) {
				configureLap(lap);

				List<TrackT> track = lap.getTrack();
				for (TrackT trackT : track) {
					for (TrackpointT trackpoint : trackT.getTrackpoint()) {
						trackPointCount++;
						Short cadence = trackpoint.getCadence();
						cadenceCount += cadence;
						double distancePerMinute = tour * cadence;
						double speedMetrePerSeconde = distancePerMinute / 60;

						TcxExt tcxExt = trackpoint.getExtensions();
						if (tcxExt == null) {
							tcxExt = new TcxExt();
							trackpoint.setExtensions(tcxExt);
						}

						TPXT tpx = tcxExt.getTPX();
						if (tpx == null) {
							tpx = new TPXT();
							tcxExt.setTPX(tpx);
						}
						tpx.setSpeed(speedMetrePerSeconde);

						// calcul puissance
						double puissanceAir = 0.5 * 1.205 * 0.9 * 0.45 * speedMetrePerSeconde * speedMetrePerSeconde
								* speedMetrePerSeconde;
						double puissanceRoulement = 0.0051 * poids * 9.81;

						double puissanceTotal = puissanceAir + puissanceRoulement;
						tpx.setWatts((int) puissanceTotal);
					}
				}
				double avgCadenceLap = (float) cadenceCount / trackPointCount;
				double avgDistancePerMinLap = tour * avgCadenceLap;
				double avgDistancePerSec = avgDistancePerMinLap / 60;

				lap.setDistanceMeters(avgDistancePerSec * lap.getTotalTimeSeconds());
			}
		}
	}

	public XMLGregorianCalendar getXmlCalendar() throws DatatypeConfigurationException {
		GregorianCalendar gregorianCalendar = new GregorianCalendar();
		gregorianCalendar.setTime(new Date());
		XMLGregorianCalendar xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar);
		return xmlCalendar;
	}

	private void configureLap(ActivityLapT lap) {
		LXT lx = lap.getExtensions().getLX();
		if (lx == null) {
			lx = new LXT();
			lap.getExtensions().setLX(lx);
		}
	}

	@SuppressWarnings("unchecked")
	public TrainingCenterDatabaseT loadGpxWithJaxb2(String fileName) throws IOException {
		FileInputStream is = null;
		try {
			is = new FileInputStream(fileName);
			return ((JAXBElement<TrainingCenterDatabaseT>) this.jaxb2Unmarshaller.unmarshal(new StreamSource(is)))
					.getValue();
		} finally {
			if (is != null) {
				is.close();
			}
		}
	}

	public void convertFromObjectToXMLWithJaxb2(Object object, String filepath) throws IOException {
		FileOutputStream os = null;
		try {
			os = new FileOutputStream(filepath);
			jaxb2Marshaller.marshal(object, new StreamResult(os));
		} finally {
			if (os != null) {
				os.close();
			}
		}
	}

	public void setJaxb2Unmarshaller(Unmarshaller jaxb2Unmarshaller) {
		this.jaxb2Unmarshaller = jaxb2Unmarshaller;
	}

	public void setJaxb2Marshaller(Marshaller jaxb2Marshaller) {
		this.jaxb2Marshaller = jaxb2Marshaller;
	}
}
